"""
星火大模型敏感词检测工具类
基于讯飞星火大模型 Spark Lite 进行内容审核和敏感词检测
"""

import json
import hmac
import base64
import hashlib
import websocket
from datetime import datetime
from urllib.parse import urlencode, urlparse
from typing import Dict, Any, Optional, Tuple
import logging
from config import get_settings

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class SparkContentChecker:
    """
    星火大模型内容检测器
    用于检测文本内容是否包含敏感词汇
    """
    
    def __init__(self):
        """
        初始化星火内容检测器
        """
        self.settings = get_settings()
        self.app_id = self.settings.spark_app_id
        self.api_key = self.settings.spark_api_key
        self.api_secret = self.settings.spark_api_secret
        self.spark_url = self.settings.spark_lite_url
        
        # 检测结果
        self.result = None
        self.error = None
        
    def create_url(self) -> str:
        """
        创建鉴权URL
        
        Returns:
            str: 鉴权后的WebSocket URL
        """
        # 生成RFC1123格式的时间戳（使用UTC时间）
        from datetime import datetime, timezone
        now = datetime.now(timezone.utc)
        date = now.strftime('%a, %d %b %Y %H:%M:%S GMT')
        
        # 拼接字符串
        signature_origin = f"host: spark-api.xf-yun.com\ndate: {date}\nGET /v1.1/chat HTTP/1.1"
        
        # 进行hmac-sha256进行加密
        signature_sha = hmac.new(
            self.api_secret.encode('utf-8'), 
            signature_origin.encode('utf-8'),
            digestmod=hashlib.sha256
        ).digest()
        
        signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding='utf-8')
        
        authorization_origin = f'api_key="{self.api_key}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"'
        
        authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8')
        
        # 将请求的鉴权参数组合为字典
        v = {
            "authorization": authorization,
            "date": date,
            "host": "spark-api.xf-yun.com"
        }
        
        # 拼接鉴权参数，生成url
        url = self.spark_url + '?' + urlencode(v)
        return url
        
    def gen_params(self, content: str) -> Dict[str, Any]:
        """
        生成请求参数
        
        Args:
            content (str): 要检测的文本内容
            
        Returns:
            Dict[str, Any]: 请求参数字典
        """
        # 构建敏感词检测的提示词
        system_prompt = """你是一个专业的内容审核助手。请检查用户输入的文本是否包含以下类型的敏感内容：
                        1. 政治敏感内容
                        2. 色情低俗内容  
                        3. 暴力恐怖内容
                        4. 违法违规内容
                        5. 辱骂攻击内容
                        6. 广告推广内容
                        请直接回答"安全"或"敏感，敏感原因"，如果是敏感内容，请说明原因。"""
        
        data = {
            "header": {
                "app_id": self.app_id,
                "uid": "content_check_user"
            },
            "parameter": {
                "chat": {
                    "domain": "lite",
                    "temperature": 0.1,
                    "max_tokens": 1000
                }
            },
            "payload": {
                "message": {
                    "text": [
                        {
                            "role": "system",
                            "content": system_prompt
                        },
                        {
                            "role": "user", 
                            "content": content
                        }
                    ]
                }
            }
        }
        return data
        
    def on_error(self, ws, error):
        """
        WebSocket错误回调
        
        Args:
            ws: WebSocket连接对象
            error: 错误信息
        """
        logger.error(f"WebSocket连接错误: {error}")
        self.error = str(error)
        
    def on_close(self, ws, close_status_code, close_msg):
        """
        WebSocket关闭回调
        
        Args:
            ws: WebSocket连接对象
            close_status_code: 关闭状态码
            close_msg: 关闭消息
        """
        logger.info("WebSocket连接已关闭")
        
    def on_open(self, ws):
        """
        WebSocket连接建立回调
        
        Args:
            ws: WebSocket连接对象
        """
        logger.info("WebSocket连接已建立")
        
    def on_message(self, ws, message):
        """
        WebSocket消息接收回调
        
        Args:
            ws: WebSocket连接对象
            message: 接收到的消息
        """
        try:
            logger.debug(f"收到消息: {message}")
            data = json.loads(message)
            
            # 检查响应头部
            header = data.get('header', {})
            code = header.get('code', -1)
            
            if code != 0:
                logger.error(f"请求错误，错误码: {code}, 错误信息: {data}")
                self.error = f"API错误: {code}"
                ws.close()
                return
            
            # 获取响应状态
            sid = header.get('sid', '')
            status = header.get('status', 0)
            
            # 解析payload数据
            payload = data.get("payload", {})
            
            # 处理不同的响应格式
            if payload:
                # 检查是否有choices字段（生成式响应）
                choices = payload.get("choices", {})
                if choices and "text" in choices:
                    text_list = choices.get("text", [])
                    if text_list and len(text_list) > 0:
                        content = text_list[0].get("content", "")
                        if content:
                            if self.result is None:
                                self.result = ""
                            self.result += content
                            logger.debug(f"累积内容: {self.result}")
                
                # 检查是否有直接的结果字段（检测响应）
                elif "result" in payload:
                    result_data = payload.get("result", {})
                    if isinstance(result_data, dict):
                        # 提取检测结果
                        detection_result = result_data.get("detection", "")
                        if detection_result:
                            self.result = detection_result
                            logger.info(f"检测结果: {detection_result}")
                    elif isinstance(result_data, str):
                        self.result = result_data
                        logger.info(f"检测结果: {result_data}")
            
            # 检查是否完成
            if status == 2:  # 消息接收完毕
                logger.info(f"消息接收完毕，最终结果: {self.result}")
                ws.close()
                
        except json.JSONDecodeError as e:
            logger.error(f"JSON解析错误: {e}")
            logger.error(f"原始消息: {message}")
            self.error = f"JSON解析失败: {str(e)}"
            ws.close()
        except Exception as e:
            logger.error(f"处理消息时出错: {e}")
            logger.error(f"消息内容: {message}")
            self.error = f"消息处理异常: {str(e)}"
            ws.close()
            
    def check_content(self, content: str, timeout: int = 10) -> Tuple[bool, str]:
        """
        检查内容是否包含敏感信息
        
        Args:
            content (str): 要检测的文本内容
            timeout (int): 超时时间（秒）
            
        Returns:
            Tuple[bool, str]: (是否敏感, 检测结果详情)
        """
        if not content or not content.strip():
            logger.info("内容为空，跳过检测")
            return False, "内容为空"
            
        logger.info(f"开始检测内容: {content[:50]}{'...' if len(content) > 50 else ''}")
        
        try:
            # 重置状态
            self.result = None
            self.error = None
            
            # 创建WebSocket连接
            url = self.create_url()
            logger.debug(f"WebSocket连接URL: {url}")
            
            ws = websocket.WebSocketApp(
                url,
                on_message=self.on_message,
                on_error=self.on_error,
                on_close=self.on_close,
                on_open=self.on_open
            )
            
            # 生成请求参数
            params = self.gen_params(content)
            
            def run_with_data():
                ws.send(json.dumps(params))
                
            ws.on_open = lambda ws: run_with_data()
            
            logger.info("启动WebSocket连接...")
            # 运行WebSocket连接
            ws.run_forever(ping_interval=60, ping_timeout=5)
            
            # 检查是否有错误
            if self.error:
                logger.error(f"检测过程中发生错误: {self.error}")
                return False, f"检测失败: {self.error}"
                
            # 检查结果
            if self.result is None:
                logger.warning("未收到检测响应")
                return False, "检测失败: 未收到响应"
                
            # 解析检测结果 - 改进判断逻辑
            result_text = self.result.strip()
            logger.info(f"原始检测结果: {result_text}")
            
            # 转换为小写进行匹配
            result_lower = result_text.lower()
            
            # 定义敏感内容关键词
            sensitive_keywords = [
                "敏感", "不当", "违规", "不安全", "不合适", "不良", "有害",
                "sensitive", "unsafe", "inappropriate", "harmful", "violation",
                "违反", "禁止", "限制", "屏蔽", "过滤", "拦截"
            ]
            
            # 定义安全内容关键词
            safe_keywords = [
                "安全", "正常", "合规", "通过", "允许", "可以",
                "safe", "normal", "compliant", "pass", "allowed", "ok"
            ]
            
            # 首先检查是否包含敏感关键词
            is_sensitive = any(keyword in result_lower for keyword in sensitive_keywords)
            
            # 如果没有明确的敏感标识，检查是否有安全标识
            if not is_sensitive:
                is_safe = any(keyword in result_lower for keyword in safe_keywords)
                # 如果既没有敏感标识也没有安全标识，根据内容长度和特征判断
                if not is_safe:
                    # 如果返回内容很长且包含解释性文字，可能是敏感内容的详细说明
                    if len(result_text) > 50 and ("因为" in result_text or "由于" in result_text or "根据" in result_text):
                        is_sensitive = True
                        logger.warning(f"根据内容特征判断为敏感: {result_text[:100]}...")
            
            logger.info(f"检测判断结果: {'敏感' if is_sensitive else '安全'}")
            return is_sensitive, self.result
            
        except Exception as e:
            logger.error(f"内容检测异常: {e}")
            return False, f"检测异常: {str(e)}"
            
    def batch_check_content(self, contents: list, timeout: int = 30) -> Dict[str, Tuple[bool, str]]:
        """
        批量检查内容
        
        Args:
            contents (list): 要检测的文本内容列表
            timeout (int): 总超时时间（秒）
            
        Returns:
            Dict[str, Tuple[bool, str]]: 检测结果字典，key为内容，value为(是否安全, 检测结果)
        """
        results = {}
        
        for content in contents:
            if not content or not content.strip():
                results[content] = (True, "空内容，跳过检测")
                continue
                
            is_safe, result = self.check_content(content, timeout // len(contents))
            results[content] = (is_safe, result)
            
        return results


async def check_sensitive_content(content: str) -> tuple[bool, str]:
    """
    检测内容是否包含敏感词的便捷函数
    
    Args:
        content: 要检测的文本内容
        
    Returns:
        tuple: (是否敏感, 详细信息)
    """
    try:
        settings = get_settings()
        
        # 检查配置是否完整
        if (not settings.spark_app_id or settings.spark_app_id == "your-spark-app-id" or
            not settings.spark_api_key or settings.spark_api_key == "your-spark-api-key" or
            not settings.spark_api_secret or settings.spark_api_secret == "your-spark-api-secret"):
            # 如果配置不完整，跳过敏感词检测，直接返回正常
            print("星火大模型配置不完整，跳过敏感词检测")
            return False, "配置不完整，跳过检测"
        
        checker = SparkContentChecker()
        
        # 注意：check_content是同步方法，不需要await
        return checker.check_content(content)
    except Exception as e:
        # 如果检测失败，记录错误但不阻止用户操作
        print(f"敏感词检测失败: {str(e)}")
        return False, f"检测失败: {str(e)}"


if __name__ == "__main__":
    # 测试代码
    test_content = "这是一个测试内容"
    is_safe, result = check_sensitive_content(test_content)
    print(f"内容: {test_content}")
    print(f"检测结果: {'安全' if is_safe else '敏感'}")
    print(f"详细信息: {result}")